#ifndef HMS_FORMAT_HELPERS_HPP
#define HMS_FORMAT_HELPERS_HPP

#ifdef SPDLOG_FMT_EXTERNAL
	#include <fmt/color.h>
#else
	#include <spdlog/fmt/bundled/color.h>
#endif

#include <magic_enum.hpp>
#include <cassert>

namespace hms
{

#define HMS_FORMAT_SHORTHAND(FUNC_NAME, FORMAT_BITS) \
template<typename ... Args> \
auto FUNC_NAME( std::string_view format_str, Args&& ... args ){ \
	return fmt::format( FORMAT_BITS, format_str, std::forward<Args>(args) ... ); \
}

HMS_FORMAT_SHORTHAND( bold, fmt::emphasis::bold )
HMS_FORMAT_SHORTHAND( italic, fmt::emphasis::italic )
HMS_FORMAT_SHORTHAND( underline, fmt::emphasis::underline )
HMS_FORMAT_SHORTHAND( green, fmt::fg(fmt::terminal_color::green) )
HMS_FORMAT_SHORTHAND( yellow, fmt::fg(fmt::rgb(255,255,0) ) )
HMS_FORMAT_SHORTHAND( red, fmt::fg(fmt::terminal_color::red) )

template<typename ... Args>
auto rgb( int r, int g, int b, std::string_view format_str, Args&& ... args ){
	return fmt::format(
		fmt::fg( fmt::rgb(r,g,b) ),
		format_str,
		std::forward<Args>(args) ...
	);
}

constexpr int indentSize {4};

inline auto indent(int level = 1){
	assert(level >= 1);
	return fmt::format( "{0:<{1}}", "", indentSize*level );
}

template<typename EnumType, bool excludeLast = false>
inline auto enumValuesToString(int indentLevel = 1){
	fmt::memory_buffer options;
	static constexpr int iMax { magic_enum::enum_count<EnumType>() - excludeLast };
	for ( int i{0}; i<iMax; ++i )
		fmt::format_to(std::back_inserter(options),
			"\n{}{}", indent(indentLevel),
			magic_enum::enum_name( static_cast<EnumType>(i) )
		);
	return fmt::to_string(options);
}

template<typename ... Args>
int maxDecimalDigits( Args&& ... args ){
	/* floor(log10) + 1 is number of digits */ 
	return static_cast<int>(
		std::floor(std::log10(std::max({ static_cast<double>(args) ... })))
	) + 1;
}

} // namespace hms


#endif